<?php

namespace App\Http\Model;

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class WishDefender extends Base
{
    protected $luckDrawPoolsUserProp = 'wish_defender_user_prop';//恋爱卡
    protected $luckDrawPoolsUserPropLog = 'wish_defender_user_prop_log';//恋爱卡日志

    protected $table = 'wish_defender_config';
    protected $luckBaseTable = 'wish_defender_price';//许愿池基本配置
    protected $wPoolTable = 'wish_defender_pool';
    protected $wPoolConfigTable = 'wish_defender_pool_config';
    protected $wOrderTable = 'wish_defender_order';
    protected $wDrawTable = 'wish_defender_draw';
    protected $wWinnerTable = 'wish_defender_winner';
    protected $wStageTable = 'wish_defender_send_gift';
    protected $wWhiteTable = 'wish_defender_white';
    protected $wStatisticsTable = 'wish_defender_statistics';
    protected $giftTable = 'gift_library';
    protected $wGiftTable = 'wish_defender_gift';//展示礼物表
    protected $wDefenderUserTable = 'wish_defender_pool_user';//个人池用户

    //许愿池配置缓存
    protected $wishDefenderConfigKey = 'DEFENDER:CONFIG';//string DEFENDER:CONFIG => {string}
    protected $wishDefenderStageKey = 'DEFENDER:STAGE';//string DEFENDER:CONFIG => {string}
    //许愿池奖池缓存
    protected $wishLuckPoolKey = 'DEFENDER:POOL';//string DEFENDER:POOL => {string}
    //许愿池奖池配置缓存
    protected $wishLuckPoolConfigKey = 'DEFENDER:POOLCONFIG:';//string DEFENDER:POOLCONFIG:{poolId} => {string}
    //许愿池奖池配置数据缓存
    public $wishLuckPoolDataKey = '{DEFENDER:POOLDATA:%s:%s}'; //奖池 {DEFENDER:POOLDATA:{$level }:{poolId}}
    //许愿池个人奖池
    public $wishLuckSelfPoolDataKey = '{DEFENDER:USERPOOLDATA:%s:%s:%s}';//奖池 {DEFENDER:USERPOOLDATA:{userId}:{$level}:{$poolId}}

    //许愿池展示礼物缓存
    protected $wishPoolsGiftKey = 'DEFENDER:GIFTCONFIG:';//string DEFENDER:GIFTCONFIG:{pool_level} => {string}
    //许愿池用户每周抽奖次数缓存
    protected $userDrawNumWeekKey = 'DEFENDER:USERDRAW:WEEKNUM:';//string DEFENDER:USERDRAW:WEEKNUM:{ymd}:{userid} => {num}
    protected $_redisKeyUserExpNum = 'DEFENDER:CACHE:USER:EXP:%d:%s';//使用过的告白币

    //当前擂主
    public $winnerKey = 'DEFENDER:WINNER:USER';//string DEFENDER:WINNER => {string}
    //擂主倒计时
    public $winnerCountdown = 'DEFENDER:WINNER:COUNTDOWN';//string DEFENDER:COUNTDOWN => {string}
    // 擂主时间增加次数
    public $winnerIncrNum = 'DEFENDER:WINNER:INCR:NUM';//string DEFENDER:INCR:NUM => {string}

    public $allProgressValue = 'DEFENDER:PROGRESS:VALUE';//全服进度值
    public $defenderLuckId = 'DEFENDER:LUCKID';//当前池子id
    public $defenderEndTime = 'DEFENDER:ENDTIME';//结束时间 秒
    public $rapidMode = 'DEFENDER:RAPID:MODE';//无限乱斗模式
    public $countdownMode = 'DEFENDER:COUNTDOWN:MODE';//倒计时模式
    public $countdownLock = 'DEFENDER:COUNTDOWN:LOCK';//倒计时锁

    const USER_PROP_TYPE_EXCHANGE = 1000; //钻石兑换道具
    const USER_PROP_TYPE_DRAW = 2000;     //抽奖消耗
    const USER_PROP_TYPE_RECYCLE = 2001;     //回收消耗

    const WINNER_MAX_INCR = 5;// 擂主最多叠加次数
    const WINNER_INCR_TIME = 180;// 擂主每次叠加时间
    const WINNER_INIT_TIME = 900;// 擂主初始时间

    const WINNER_INCR_TIME_NEW = [
        1000 => 180,
        1001 => 120,
        1002 => 60,
        1003 => 30,
    ];

    const LUCK_NAME = [
        1000 => '一阶段圣战奖励',
        1001 => '二阶段圣战奖励',
        1002 => '三阶段圣战奖励',
        1003 => '四阶段圣战奖励',
    ];


    const USER_PROP_TYPE_DESC = [
        //抽奖页面用钻石兑换
        self::USER_PROP_TYPE_EXCHANGE => '钻石兑换',
        //抽奖页面抽奖消耗
        self::USER_PROP_TYPE_DRAW => '抽奖消耗',
        self::USER_PROP_TYPE_RECYCLE => '回收消耗',
    ];

    public  function getDescFromType($type){
        return self::USER_PROP_TYPE_DESC[$type]??'';
    }

    public function __construct(array $attributes = [])
    {
        parent::__construct($this->table, $attributes);
    }

    /**
     * 抽奖活动详情
     */
    public function luckDrawInfo($luckId){
        $info = DB::table($this->luckBaseTable)->where('id', $luckId)->first();
        $info = self::objToArray($info);

        return $info;
    }

    public function getLuckName($luckId) {
        return self::LUCK_NAME[$luckId]??'';
    }

    /**
     * 许愿池中奖记录列表
     */
    public function awardListV2($page, $limit, $where){
        $query = DB::table($this->wWinnerTable);
        if(!empty($where['user_id'])) {
            $query = $query->where('user_id', $where['user_id']);
        }
        if(!empty($where['created_at_st'])) {
            $query = $query->where('created_at', '>=', $where['created_at_st']);
        }
        $query = $query->selectRaw('gift_id, user_id, created_at,pool_level')
            ->orderBy('id', 'desc')
            ->offset($page * $limit)->limit($limit);
        $drawList = $query->get();
        $result = self::objToArray($drawList);

        return $result;
    }

    /**
     * 获取万神殿配置信息
     */
    public function getWishDefenderConfig(){
        $key = $this->wishDefenderConfigKey;
        $list = Redis::get($key);
        $list = false;
        if(empty($list)){
            $list = DB::table($this->table)->first();
            $list = self::objToArray($list);
            if(!empty($list)) {
                Redis::setex($key,86400, json_encode($list));
            }
        }else{
            $list = json_decode($list, true);
        }

        return $list;
    }



    public function updateGameRule($data)
    {
        $gameRule = $data['gameRule'];
        $res = DB::table($this->table)->where("id", "=", '1')->update(['rule' => $gameRule]);
        if ($res) {
            $key = $this->wishDefenderConfigKey;
            $list = DB::table($this->table)->first();
            $list = self::objToArray($list);
            if (!empty($list)) {
                Redis::setex($key, 86400, json_encode($list));
            }
        }
    }


    public function getGameRule()
    {
        $key = $this->wishDefenderConfigKey;
        $list = Redis::get($key);
        if(empty($list)){
            $list = DB::table($this->table)->first();
            $list = self::objToArray($list);
            if(!empty($list)) {
                Redis::setex($key,86400, json_encode($list));
            }
        }

        return $list;
    }


    /**
     * 获取万神殿池阶段信息
     */
    public function getStageInfo($level){
        $config = $this->getWishDefenderConfig();
        $ret = [
            'gift_id' => '',
            'limit' => 0,
        ];
        if ($level == 1000) {
            $ret['gift_id'] = $config['send_defender_gift1'];
            $ret['limit'] = $config['set_defender_num1'];
        } elseif ($level == 1001) {
            $ret['gift_id'] = $config['send_defender_gift2'];
            $ret['limit'] = $config['set_defender_num2'];
        }  elseif ($level == 1002) {
            $ret['gift_id'] = $config['send_defender_gift3'];
            $ret['limit'] = $config['set_defender_num3'];
        }  elseif ($level == 1003) {
            $ret['gift_id'] = $config['send_defender_gift4'];
            $ret['limit'] = $config['set_defender_num4'];
        }

        return $ret;

//        $key = $this->wishDefenderStageKey;
//        $info = Redis::get($key);
//        if(empty($info)){
//            $info = DB::table($this->wStageTable)
//                ->where('pool_level', $level)
//                ->where('is_delete', 0)
//                ->first();
//            $info = self::objToArray($info);
//            if(!empty($info)) {
//                Redis::setex($key,86400, json_encode($info));
//            }
//        }else{
//            $info = json_decode($info, true);
//        }
//
//        return $info;
    }

    /**
     * 获取个人池配置
     */
    public function getPoolUser($userId, $level){
        $info = DB::table($this->wDefenderUserTable)
            ->where('user_id', $userId)
            ->where('pool_level', $level)
            ->where('is_delete', 0)
            ->first();
        $info = self::objToArray($info);

        return $info;
    }

    /**
     * 万神殿奖池信息
     */
    public function getPool($luckId){
        $key = $this->wishLuckPoolKey.$luckId;
        $list = Redis::get($key);
        if(empty($list)){
            $list = DB::table($this->wPoolTable)->where('pool_level',$luckId)->get();
            $list = self::objToArray($list);
            if(!empty($list)) {
                Redis::setex($key, 86400, json_encode($list));
            }
        }else{
            $list = json_decode($list, true);
        }

        $list = array_column($list, null, 'id');

        return $list;
    }

    /**
     * 获取许愿池奖池配置
     */
    public function getWishLuckPoolConfig($poolId){
        $key = $this->wishLuckPoolConfigKey.$poolId;
        $list = Redis::get($key);
        if(empty($list)){
            $list = DB::table($this->wPoolConfigTable)->where('pool_id', $poolId)->get();
            $list = self::objToArray($list);
            if(!empty($list)) {
                Redis::setex($key, 86400, json_encode($list));
            }
        }else{
            $list = json_decode($list, true);
        }

        return $list;
    }

    /**
     * 获取万神殿用户每周抽奖次数缓存
     */
    public function getUserWishLuckDrawNumByWeek($userId, $luckId){
        $startWeek = Carbon::today()->startOfWeek()->toDateString();
        $endWeek = Carbon::today()->endOfWeek()->toDateString();
        $cacheKey = $this->userDrawNumWeekKey.$luckId.'|'.$startWeek.'|'.$endWeek.':'.$userId;
        $num = Redis::get($cacheKey);
        if(empty($num)) {
            $query = DB::table($this->wOrderTable)
                ->where('created_at', '>=', $startWeek.' 00:00:00')
                ->where('created_at', '<=',  $endWeek.' 23:59:59')
                ->where('pool_level', $luckId)
                ->where('user_id', $userId);
            $num = $query->sum('num');
        }
        $num = (int) $num;

        Redis::set($cacheKey, $num);
        Redis::expire($cacheKey, 14*86400);

        return $num;
    }

    /**
     * 获取用户白名单
     */
    public function getWishLuckWhite($userId, $luckId){
        $list = DB::table($this->wWhiteTable)
            ->where('user_id', $userId)
            ->where('status', 0)
            ->where('pool_level', $luckId)
            ->where('is_delete', 0)
            ->get();
        $list = self::objToArray($list);

        return $list;
    }

    //新增万神殿订单记录
    public function addWishLuckOrder($data)
    {
        $id = DB::table($this->wOrderTable)->insertGetId($data);

        return $id;
    }

    //新增万神殿擂主记录
    public function addWinner($data)
    {
        $id = DB::table($this->wWinnerTable)->insertGetId($data);

        return $id;
    }

    //万神殿自指定奖池抽取
    public function drawWishLuckUser($level,$poolId, $userId)
    {
        $key = sprintf($this->wishLuckSelfPoolDataKey, $level ,$userId, $poolId);
        $poolConfigId = aliasIndex($key);

        return $poolConfigId;
    }

    //许愿转盘自指定奖池抽取
    public function drawWishLuck($level, $poolId)
    {
        $key = sprintf($this->wishLuckPoolDataKey, $level, $poolId);
        $poolConfigId = aliasIndex($key);

        return $poolConfigId;
    }

    // 成为擂主
    public function setWinner($userId)
    {
        $luckId = (int)Redis::get($this->defenderLuckId);
        $luckId = empty($luckId) ? 1000 : $luckId;

        $incrTime = self::WINNER_INCR_TIME_NEW[$luckId] ?? 120;

        $rapidMode = Redis::get($this->rapidMode);

        if ($luckId == 1003 && $rapidMode == 1) {
            // 无限乱斗模式
            $incrTime = 10;
        }

        $countdown = Redis::get($this->winnerCountdown);
//        if ($countdown <= 1) {
//            sleep(2);
//        }
        Redis::SET($this->winnerKey, $userId);

//        $countdown = Redis::get($this->winnerCountdown);

        if (($countdown + $incrTime) >= self::WINNER_INIT_TIME) {
            Redis::SET($this->winnerCountdown, self::WINNER_INIT_TIME);
        } else {
            Redis::INCRBY($this->winnerCountdown, $incrTime);
        }

        return true;
    }

    // 查询擂主
    public function getWinner()
    {
        return Redis::get($this->winnerKey) ?: '';
    }

    // 获取倒计时
    public function getWinnerCountdown() {
        $time = (int)Redis::get($this->winnerCountdown);
        return $time ?: 0;
    }

    // 倒计时减少
    public function decrWinnerCountdown($num = 1) {
        return Redis::DECRBY($this->winnerCountdown, $num);
    }

    public function endStage() {
        // 清空擂主
        $this->setWinner('');

        // 清空已抽取次数
        Redis::set($this->allProgressValue, 0);

        // 清空增加计时次数
        Redis::set($this->winnerIncrNum, 0);

        // 清除无限乱斗模式
        Redis::set($this->rapidMode, 0);

        // 清除倒计时模式
        Redis::set($this->countdownMode, 0);
    }

    //新增许愿池抽奖记录
    public function addWishLuckDraw($data)
    {
        $id = DB::table($this->wDrawTable)->insertGetId($data);

        return $id;
    }

    //更新许愿池白名单
    public function updateWishLuckWhite($id, $orderId)
    {
        $res = DB::table($this->wWhiteTable)->where('id', $id)->update(['status'=>1, 'order_id'=>$orderId]);

        return $res;
    }

    //更新万神殿订单记录
    public function updateWishLuckDraw($orderId, $rewardDiamondNum, $endTime)
    {
        $res = DB::table($this->wOrderTable)->where('id', $orderId)->update(['reward_diamond_num'=>$rewardDiamondNum, 'created_at' => $endTime]);
        $res = DB::table($this->wDrawTable)->where('order_id', $orderId)->update(['created_at' => $endTime]);

        return $res;
    }

    //更新许愿池个人池用户记录
    public function updateWishLuckUserPoolLog($id, $propDiamondNum, $rewardDiamondNum, $drawNum)
    {
        $res = DB::table($this->wDefenderUserTable)->where('id', $id)->increment('prop_diamond_num', $propDiamondNum);
        $res = DB::table($this->wDefenderUserTable)->where('id', $id)->increment('reward_diamond_num', $rewardDiamondNum);
        $res = DB::table($this->wDefenderUserTable)->where('id', $id)->increment('draw_num', $drawNum);

        return $res;
    }

    //累加星辰变用户每周抽奖次数缓存
    public function incrUserDrawWeekNum($userId, $num, $luckId)
    {
        if($num <= 0) {
            return false;
        }
        $startWeek = Carbon::today()->startOfWeek()->toDateString();
        $endWeek = Carbon::today()->endOfWeek()->toDateString();
        $cacheKey = $this->userDrawNumWeekKey.$luckId.'|'.$startWeek.'|'.$endWeek.':'.$userId;
        $new = Redis::INCRBY($cacheKey, $num);

        return $new;
    }


    /**
     * 许愿池订单中奖记录列表
     */
    public function orderAwardList($orderId){
        $info = DB::table($this->wOrderTable)->where('id', $orderId)->first();
        $info = self::objToArray($info);
        if(empty($info)) {
            return [];
        }

        $drawList = DB::table($this->wDrawTable)
            ->where('order_id', $orderId)
            ->selectRaw('sum(gift_num) as gift_num, sum(prop_diamond_num) as prop_diamond_num, sum(reward_diamond_num) as reward_diamond_num, gift_id, pool_level')
            ->groupBy('gift_id')
            ->get();
        $drawList = self::objToArray($drawList);
        if(empty($drawList)) {
            return [];
        }
        $info['drawList'] = $drawList;

        return $info;
    }

    /**
     * 获取使用过的告白币
     */
    public function getUsed($userId, $luckId){
        $week = date('Y-m-d', strtotime('this week'));
        $key = sprintf($this->_redisKeyUserExpNum, $luckId, $week);
        return intval(Redis::HGET($key, $userId)??0);
    }

    /**
     * 获取用户中奖记录
     */
    public function wishLuckAllAwardList($page, $limit, $where){
        $drawList = DB::table($this->wDrawTable)
            ->where('user_id', $where['user_id'])
            ->orderBy('id','DESC')
            ->offset($page * $limit)
            ->limit($limit)
            ->get();
        $result = self::objToArray($drawList);

        return $result;
    }


    /**
     * 获取许愿池展示礼物
     */
    public function getWishLuckGift($luckId){
        $key = $this->wishPoolsGiftKey.$luckId;
        $list = Redis::get($key);
        if(empty($list)){
            $list = DB::table($this->wGiftTable)->where('is_delete', 0)->orderBy('sort', 'asc')->where('pool_level',$luckId)->get();
            $list = self::objToArray($list);
            if(!empty($list)) {
                Redis::setex($key, 86400, json_encode($list));
            }
        }else{
            $list = json_decode($list, true);
        }

        return $list;
    }


    //统计许愿池数据
    public function wishPoolStatistics($dateSt, $dateEt, $poolLevel)
    {
        $info = DB::table($this->wOrderTable)
            ->where('created_at', '>=', $dateSt)
            ->where('created_at', '<=', $dateEt)
            ->where('pool_level', $poolLevel)
            ->selectRaw('count(DISTINCT user_id) as user_num, sum(num) as draw_num, sum(prop_num) as prop_num, sum(prop_diamond_num) as prop_diamond_num, sum(reward_diamond_num) as reward_diamond_num,pool_level')
            ->first();
        $info = self::objToArray($info);

        return $info;
    }

    //新增许愿池每日统计
    public function addWishPoolStatistics($data)
    {
        $id = DB::table($this->wStatisticsTable)->insertGetId($data);

        return $id;
    }

    //获取许愿池爆出记录
    public function getDrawList($orderId){
        $list = DB::table($this->wDrawTable)
            ->select(DB::raw('sum(gift_num) as gift_num, gift_id,pool_level'))
            ->where('order_id',$orderId)
            ->groupBy('gift_id')
            ->get();
        $list = self::objToArray($list);
        return $list;
    }

    //增加用户恋爱卡
    public function addTiket(int $luckId, int $userId, int $num){
        $exist = DB::table($this->luckDrawPoolsUserProp)
            ->where('luck_id', $luckId)
            ->where('user_id', $userId)
            ->where('status', 1)
            ->where('deleted', 0)
            ->exists();

        //如果存在
        if ($exist) {
            $count = DB::table($this->luckDrawPoolsUserProp)
                ->where('luck_id', $luckId)
                ->where('user_id', $userId)
                ->where('status', 1)
                ->where('deleted', 0)
                ->increment("avail", $num);
            return $count > 0;
        }

        //如果不存在
        $insert = [
            'luck_id' => $luckId,
            'user_id' => $userId,
            'avail' => $num,
            'used' => 0,
            'status' => 1,
            'deleted' => 0
        ];
        $status = DB::table($this->luckDrawPoolsUserProp)->insert($insert);
        return $status;
    }

    //记录购买恋爱卡日志
    public function addTiketLog(int $luckId, int $userId, int $type, int $change){
        if (empty($luckId) || empty($userId) || empty($type)) {
            return false;
        }
        $insert = [
            'luck_id' => $luckId,
            'user_id' => $userId,
            'type' => $type,
            'change' => $change,
            'desc' => $this->getDescFromType($type)
        ];
        $status = DB::table($this->luckDrawPoolsUserPropLog)->insert($insert);
        return $status;
    }

    //获取可用恋爱卡
    public function getAvail(int $luckId, int $userId){
        $userPropModel = DB::table($this->luckDrawPoolsUserProp)
            ->where('luck_id', $luckId)
            ->where('user_id', $userId)
            ->where('status', 1)
            ->where('deleted', 0)
            ->first();
        return (int)$userPropModel->avail;
    }

    /**
     * 扣减用户恋爱卡
     * @return bool
     */
    public function decrUniverseTickerUserProp($userId, $luckId, $num){
        try {
            if(empty($userId) || empty($num)) {
                return false;
            }
            $num = abs($num);

            $res = DB::table($this->luckDrawPoolsUserProp)
                ->where('luck_id', $luckId)
                ->where('user_id', $userId)
                ->where('status', 1)
                ->where('deleted', 0)
                ->update([
                    'avail' =>DB::raw('`avail`-' . $num),
                    'used' =>DB::raw('`used`+' . $num),
                ]);
            if(empty($res)) {
                return false;
            }

            $log = [
                "luck_id" => $luckId,
                "user_id" => $userId,
                "change" => 0-$num,
                "type" => 2000,
                "desc" => '万神殿消耗',
            ];
            $logId = DB::table($this->luckDrawPoolsUserPropLog)->insertGetId($log);
            if(empty($logId)) {
                return false;
            }
        } catch (\Exception $e) {
            return false;
        }

        return true;
    }
}
